#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdbool.h>

#define WIDTH 60
#define HEIGHT 20
#define INIT_LENGTH 5

// 全局变量
int snakeX[100], snakeY[100]; // 蛇身坐标
int snakeLength;              // 蛇的长度
int foodX, foodY;             // 食物坐标
int direction;                // 蛇的移动方向
int score;                    // 当前得分
int highestScore;             // 最高分
int sleeptime = 200;          // 蛇移动速度
bool gameOver;                // 游戏结束标志

// 方向常量
enum Dir { STOP = 0, LEFT, RIGHT, UP, DOWN };

// 函数声明
void printsnake();
void welcometogame();
void createMap();
void scoreandtips();
void File_out();
void File_in();
void initsnake();
void createfood();
bool biteself();
void cantcrosswall();
void speedup();
void speeddown();
void snakemove();
void keyboardControl();
void gameover();
void explation();
void gotoxy(int x, int y);
void HideCursor();
void SetColor(int color);

// 主函数
int main() {
    system("mode con cols=80 lines=30"); // 设置控制台窗口大小
    HideCursor();                        // 隐藏光标
    File_out();                         // 读取最高分
    welcometogame();                    // 显示欢迎界面
    return 0;
}

// 打印蛇的字符画
void printsnake() {
    SetColor(10); // 绿色
    printf("\n\n");
    printf("        _____         \n");
    printf("     .-'     `-.      \n");
    printf("    /           \\     \n");
    printf("   |             |    \n");
    printf("   |,  .-.  .-.  ,|   \n");
    printf("   | )(__/  \\__)( |  \n");
    printf("   |/     /\\     \\|  \n");
    printf("   (_     ^^     _)   \n");
    printf("    \\__|IIIIII|__/   \n");
    printf("     | \\IIIIII/ |    \n");
    printf("      \\          /    \n");
    printf("       `--------`     \n\n");
    SetColor(7); // 恢复白色
}

// 欢迎界面
void welcometogame() {
    system("cls");
    printsnake();
    SetColor(11); // 浅蓝色
    printf("欢迎来到贪吃蛇游戏!\n\n");
    SetColor(7);
    printf("1. 开始游戏\n");
    printf("2. 游戏说明\n");
    printf("3. 查看最高分\n");
    printf("4. 退出游戏\n\n");
    printf("请选择(1-4): ");

    char choice = _getch();
    switch (choice) {
    case '1':
        // 初始化游戏
        initsnake();
        createMap();
        createfood();
        gameOver = false;
        direction = RIGHT;
        score = 0;
        
        // 游戏主循环
        while (!gameOver) {
            scoreandtips();
            keyboardControl();
            snakemove();
            Sleep(sleeptime);
        }
        gameover();
        break;
    case '2':
        explation();
        break;
    case '3':
        system("cls");
        printf("最高分: %d\n\n", highestScore);
        printf("按任意键返回...");
        _getch();
        welcometogame();
        break;
    case '4':
        exit(0);
    default:
        printf("\n无效输入，请重新选择!\n");
        Sleep(500);
        welcometogame();
    }
}

// 创建游戏地图
void createMap() {
    system("cls");
    SetColor(3); // 青色
    // 上边界
    for (int i = 0; i < WIDTH; i += 2) {
        gotoxy(i, 0);
        printf("■");
    }
    // 下边界
    for (int i = 0; i < WIDTH; i += 2) {
        gotoxy(i, HEIGHT - 1);
        printf("■");
    }
    // 左边界
    for (int i = 1; i < HEIGHT - 1; i++) {
        gotoxy(0, i);
        printf("■");
    }
    // 右边界
    for (int i = 1; i < HEIGHT - 1; i++) {
        gotoxy(WIDTH - 2, i);
        printf("■");
    }
    SetColor(7); // 恢复白色
}

// 显示得分和提示
void scoreandtips() {
    gotoxy(WIDTH + 10, 5);
    printf("得分: %d", score);
    gotoxy(WIDTH + 10, 7);
    printf("最高分: %d", highestScore);
    gotoxy(WIDTH + 10, 10);
    printf("操作说明:");
    gotoxy(WIDTH + 10, 11);
    printf("方向键控制移动");
    gotoxy(WIDTH + 10, 12);
    printf("F1: 加速");
    gotoxy(WIDTH + 10, 13);
    printf("F2: 减速");
    gotoxy(WIDTH + 10, 14);
    printf("ESC: 退出游戏");
}

// 从文件读取最高分
void File_out() {
    FILE *file = fopen("save.txt", "r");
    if (file == NULL) {
        highestScore = 0;
        return;
    }
    fscanf(file, "%d", &highestScore);
    fclose(file);
}

// 写入最高分到文件
void File_in() {
    FILE *file = fopen("save.txt", "w");
    if (file == NULL) {
        return;
    }
    fprintf(file, "%d", highestScore);
    fclose(file);
}

// 初始化蛇
void initsnake() {
    snakeLength = INIT_LENGTH;
    // 初始化蛇身
    for (int i = 0; i < snakeLength; i++) {
        snakeX[i] = 24 - i * 2;
        snakeY[i] = 5;
    }
    // 绘制蛇
    for (int i = 0; i < snakeLength; i++) {
        gotoxy(snakeX[i], snakeY[i]);
        if (i == 0) {
            SetColor(14); // 黄色蛇头
            printf("●");
        } else {
            SetColor(10); // 绿色蛇身
            printf("★");
        }
    }
    SetColor(7); // 恢复白色
}

// 创建食物
void createfood() {
    bool valid = false;
    while (!valid) {
        // 随机生成食物位置
        srand(time(NULL));
        foodX = (rand() % (WIDTH / 2 - 2)) * 2 + 2;
        foodY = rand() % (HEIGHT - 2) + 1;
        
        // 检查食物是否与蛇身重叠
        valid = true;
        for (int i = 0; i < snakeLength; i++) {
            if (foodX == snakeX[i] && foodY == snakeY[i]) {
                valid = false;
                break;
            }
        }
    }
    
    gotoxy(foodX, foodY);
    SetColor(12); // 红色食物
    printf("■");
    SetColor(7); // 恢复白色
}

// 判断蛇是否咬到自己
bool biteself() {
    for (int i = 1; i < snakeLength; i++) {
        if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
            return true;
        }
    }
    return false;
}

// 判断蛇是否撞墙
void cantcrosswall() {
    if (snakeX[0] <= 0 || snakeX[0] >= WIDTH - 2 || 
        snakeY[0] <= 0 || snakeY[0] >= HEIGHT - 1) {
        gameOver = true;
    }
}

// 加速
void speedup() {
    if (sleeptime > 50) {
        sleeptime -= 30;
    }
}

// 减速
void speeddown() {
    if (sleeptime < 350) {
        sleeptime += 30;
    }
}

// 蛇移动
void snakemove() {
    // 记录蛇尾位置
    int prevX = snakeX[snakeLength - 1];
    int prevY = snakeY[snakeLength - 1];
    
    // 清除蛇尾
    gotoxy(prevX, prevY);
    printf("  ");
    
    // 移动蛇身
    for (int i = snakeLength - 1; i > 0; i--) {
        snakeX[i] = snakeX[i - 1];
        snakeY[i] = snakeY[i - 1];
    }
    
    // 根据方向移动蛇头
    switch (direction) {
    case LEFT:
        snakeX[0] -= 2;
        break;
    case RIGHT:
        snakeX[0] += 2;
        break;
    case UP:
        snakeY[0]--;
        break;
    case DOWN:
        snakeY[0]++;
        break;
    }
    
    // 检查是否吃到食物
    if (snakeX[0] == foodX && snakeY[0] == foodY) {
        // 增加蛇长度
        snakeLength++;
        snakeX[snakeLength - 1] = prevX;
        snakeY[snakeLength - 1] = prevY;
        
        // 增加分数
        if (sleeptime <= 320) {
            score += 2;
        } else {
            score += 1;
        }
        
        // 加速
        speedup();
        
        // 创建新食物
        createfood();
    }
    
    // 绘制蛇
    for (int i = 0; i < snakeLength; i++) {
        gotoxy(snakeX[i], snakeY[i]);
        if (i == 0) {
            SetColor(14); // 黄色蛇头
            printf("●");
        } else {
            SetColor(10); // 绿色蛇身
            printf("★");
        }
    }
    SetColor(7); // 恢复白色
    
    // 检查游戏结束条件
    cantcrosswall();
    if (biteself()) {
        gameOver = true;
    }
}

// 键盘控制（已修改确保方向键可用）
void keyboardControl() {
    if (_kbhit()) {
        int ch = _getch();
        // 处理方向键（第一个字节是224或0）
        if (ch == 224 || ch == 0) {
            ch = _getch(); // 获取第二个字节
            switch (ch) {
                case 72: if (direction != DOWN) direction = UP; break;    // 上
                case 80: if (direction != UP) direction = DOWN; break;    // 下
                case 75: if (direction != RIGHT) direction = LEFT; break; // 左
                case 77: if (direction != LEFT) direction = RIGHT; break; // 右
            }
        }
        // 处理其他键
        else {
            switch (ch) {
                case 27: gameOver = true; break; // ESC
                case 59: speedup(); break;      // F1
                case 60: speeddown(); break;    // F2
            }
        }
    }
}

// 游戏结束界面
void gameover() {
    system("cls");
    SetColor(12); // 红色
    printf("\n\n  游戏结束!\n");
    SetColor(7);
    printf("  你的得分: %d\n", score);
    printf("  最高分: %d\n", highestScore);
    
    if (score > highestScore) {
        SetColor(14); // 黄色
        printf("  创纪录啦！最高分被你刷新啦，真棒！！！\n");
        highestScore = score;
        File_in(); // 保存最高分
    } else {
        printf("  继续努力吧~你离最高分还差: %d\n", highestScore - score);
    }
    
    SetColor(7);
    printf("\n  1. 重新开始\n");
    printf("  2. 退出游戏\n");
    printf("\n  请选择(1-2): ");
    
    char choice = _getch();
    switch (choice) {
    case '1':
        welcometogame();
        break;
    case '2':
        exit(0);
    default:
        printf("\n  无效输入，请重新选择!\n");
        Sleep(500);
        gameover();
    }
}

// 游戏说明界面
void explation() {
    system("cls");
    printf("\n\n  游戏说明:\n");
    printf("  1. 使用方向键控制蛇的移动\n");
    printf("  2. 吃到食物后蛇会变长，得分增加\n");
    printf("  3. 撞到墙壁或自己的身体游戏结束\n");
    printf("  4. 按F1加速，F2减速\n");
    printf("  5. 按ESC键可以退出游戏\n\n");
    printf("  按任意键返回...");
    _getch();
    welcometogame();
}

// 移动光标到指定位置
void gotoxy(int x, int y) {
    COORD pos = { x, y };
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOut, pos);
}

// 隐藏光标
void HideCursor() {
    CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

// 设置控制台颜色
void SetColor(int color) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}